import { any } from "../../../core/logic";
import { Engine } from "../../../Engine";
import { Pass } from "../Pass";
import { Effect, EffectType } from "./Effect";
import { colorAdjust_vert } from "./shaders/colorAdjust_vert";
import { colorAdjust_frag } from "./shaders/colorAdjust_frag";
/**
 * 后处理色彩调整
 * @class
 * @memberof w.effects
 */
class ColorAdjust extends Effect {
  /**
   * @constructor
   * @param {*} opts
   * @param {Number} opts.brightness 缺省值1.0,亮度。
   * @param {Number} opts.saturation 缺省值1.0,饱和度
   * @param {Number} opts.contrast 缺省值1.0,对比度
   */
  constructor(opts = {}) {
    super(opts);
    this.type = EffectType.ColorAdjust;
    this.sampler = Engine.instance.device.createSampler({
      magFilter: "linear", //nearest linear
      minFilter: "linear",
    });
    this.initBuffer();
    this.initPipeLine();
    this.brightness = any(opts.brightness, 1.0);
    this.saturation = any(opts.saturation, 1.0);
    this.contrast = any(opts.contrast, 1.0);
  }
  get brightness() {
    return this._brightness;
  }
  set brightness(v) {
    this._brightness = v;
    Engine.instance.queue.writeBuffer(this.brightnessBuffer, 0, new Float32Array([v]));
    this.update();
  }
  get saturation() {
    return this._saturation;
  }
  set saturation(v) {
    this._saturation = v;
    Engine.instance.queue.writeBuffer(this.saturationBuffer, 0, new Float32Array([v]));
    this.update();
    return this;
  }
  get contrast() {
    return this._contrast;
  }
  set contrast(v) {
    this._contrast = v;
    Engine.instance.queue.writeBuffer(this.contrastBuffer, 0, new Float32Array([v]));
    this.update();
    return this;
  }
  initBuffer() {
    this.brightnessBuffer = Engine.instance.device.createBuffer({
      label: "brightness",
      size: 4,
      usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,
    });
    this.saturationBuffer = Engine.instance.device.createBuffer({
      label: "saturation",
      size: 4,
      usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,
    });
    this.contrastBuffer = Engine.instance.device.createBuffer({
      label: "contrast",
      size: 4,
      usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,
    });
  }
  initPipeLine() {
    this.bindGroupLayout = Engine.instance.device.createBindGroupLayout({
      label: "colorAdjustlayout",
      entries: [
        {
          binding: 0,
          visibility: GPUShaderStage.FRAGMENT,
          sampler: {
            type: "filtering",
          },
        },
        {
          binding: 1,
          visibility: GPUShaderStage.FRAGMENT,
          texture: {
            sampleType: "float",
            viewDimension: "2d",
            multisampled: false,
          },
        },
        {
          binding: 2,
          visibility: GPUShaderStage.FRAGMENT,
          buffer: {
            type: "uniform",
          },
        },
        {
          binding: 3,
          visibility: GPUShaderStage.FRAGMENT,
          buffer: {
            type: "uniform",
          },
        },
        {
          binding: 4,
          visibility: GPUShaderStage.FRAGMENT,
          buffer: {
            type: "uniform",
          },
        },
      ],
    });
    let pipeLayout = Engine.instance.device.createPipelineLayout({
      bindGroupLayouts: [this.bindGroupLayout],
    });
    this.pipeLine = Engine.instance.device.createRenderPipeline({
      label: "colorAdjust Pipline",
      layout: pipeLayout,
      vertex: {
        module: Engine.instance.device.createShaderModule({
          code: colorAdjust_vert,
        }),
        entryPoint: "main",
      },
      fragment: {
        module: Engine.instance.device.createShaderModule({
          code: colorAdjust_frag,
        }),
        entryPoint: "main",
        targets: [
          {
            format: Engine.instance.format,
          },
        ],
      },
      primitive: {
        topology: "triangle-list",
        cullMode: "back",
        frontFace: "ccw",
      },
    });
  }
  initBindGroup(texture) {
    if (this.group && this.group.id != texture.id) {
      this.group = null;
    }
    if (!this.group) {
      this.group = Engine.instance.device.createBindGroup({
        label: "Texture Group with Texture/Sampler",
        layout: this.bindGroupLayout,
        entries: [
          {
            binding: 0,
            resource: this.sampler,
          },
          {
            binding: 1,
            resource: texture.view,
          },
          {
            binding: 2,
            resource: {
              buffer: this.brightnessBuffer,
              size: 4,
            },
          },
          {
            binding: 3,
            resource: {
              buffer: this.saturationBuffer,
              size: 4,
            },
          },
          {
            binding: 4,
            resource: {
              buffer: this.contrastBuffer,
              size: 4,
            },
          },
        ],
      });
      this.group.id=texture.id;
    }
    return this.group;
  }
  onRender(commandEncoder) {
    //执行帧渲染
    const pass = super.onRender(commandEncoder);
    const texture = Pass.instance().readAttach;
    const renderPass = commandEncoder.beginRenderPass(pass);
    renderPass.setPipeline(this.pipeLine);
    let bindGroup = this.initBindGroup(texture);
    renderPass.setBindGroup(0, bindGroup);
    renderPass.draw(3);
    renderPass.end();
  }
  getDescript() {
    if (this._descript) {
      if (
        this._descript.size[0] !== Engine.instance.size[0] ||
        this._descript.size[1] !== Engine.instance.size[1]
      ) {
        this._descript = null;
      } else {
        this._descript.colorAttachments[0].view = Pass.instance().writeAttach.view;
      }
    }
    if (!this._descript) {
      this._descript = {
        colorAttachments: [
          {
            view: Pass.instance().writeAttach.view,
            loadOp: "clear",
            clearValue: { r: 1.0, g: 1.0, b: 1.0, a: 1.0 },
            storeOp: "store",
          },
        ],
      };
      this._descript.size = Engine.instance.size;
    }
    return this._descript;
  }
}
export { ColorAdjust };
